Математика - Итоговая работа¶
Описание задания¶
В качестве итогового задания по блоку «Математика» мы предлагаем вам подготовить отчет с результатами обучения регрессионной модели. Для подготовки такого отчета от вас потребуется применить все знания и навыки, полученные за время прохождения блока. Несмотря на то, что есть ряд требований по оформлению решения и перечню проведенных тестов, мы будем рады, если вы проявите свою индивидуальность в исследуемых датасетах, выдвинутых гипотезах и дизайне.
Описание данных¶
| # | Столбец | Тип данных | Описание |
|---|---|---|---|
| 1 | airline |
object | Авиакомпания (6 уникальных значений: IndiGo, SpiceJet, AirAsia и др.) |
| 2 | flight |
object | Код рейса (уникальный идентификатор рейса) |
| 3 | source_city |
object | Город отправления (6 уникальных значений) |
| 4 | departure_time |
object | Время вылета (6 временных интервалов: Night, Morning, Afternoon и др.) |
| 5 | stops |
object | Количество пересадок (zero, one, two_or_more) |
| 6 | arrival_time |
object | Время прилета (6 временных интервалов) |
| 7 | destination_city |
object | Город прибытия (6 уникальных значений) |
| 8 | class |
object | Класс билета (Economy, Business) |
| 9 | duration |
float64 | Время в пути (часы) |
| 10 | days_left |
int64 | Оставшиеся дни до вылета |
| 11 | price |
float64 | Целевая переменная – цена авиабилета |
Цели и задачи¶
- Разведочный анализ (EDA)
- Изучить распределения признаков и различия между сегментами (с помощью гистограмм, плотностей, PSI, KS).
- Сформировать общую картину, выявить аномалии и особенности данных.
- Проверка статистических гипотез
- Сформулировать и протестировать несколько гипотез о разнице ключевых показателей (цены, длительность и т.п.) между группами.
- Построить точечные и интервальные (бутстрэп) оценки разницы средних и сделать вывод о статистической значимости.
- Предложить гипотезы и дальнейшие эксперименты по улучшению отстающих групп.
- Регрессионный анализ
- Построить линейную регрессию (МНК), интерпретировать коэффициенты.
- Проверить модель на гетероскедастичность, мультиколлинеарность и при необходимости скорректировать спецификацию.
- Сравнить несколько моделей и обосновать выбор финальной.
- Визуализация и оформление результатов
- Оформить графики (статические и интерактивные) с подписями и краткими комментариями.
- Структурировать работу (введение, методология, результаты, выводы) и представить её в аккуратном виде.
Дополнительный комментарий¶
Долго выбирал датасет и вот под конец работы кажется, что ошибся с выбором, хотя сам датасет и интересный. Надеюсь, что все же большинство получилось релизовать правильно.
Импорт библиотек и настройка дополнительных параметров¶
In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
import plotly.figure_factory as ff
import mplcyberpunk
import scipy.stats as st
import statsmodels.api as sm
from statsmodels.stats.diagnostic import het_breuschpagan
from statsmodels.stats.outliers_influence import variance_inflation_factor
from phik import resources
from phik.report import plot_correlation_matrix
from IPython.display import display
In [2]:
plt.style.use("cyberpunk")
plt.rcParams['figure.autolayout'] = True
plt.rcParams['axes.titleweight'] = 'bold'
Загрузка датасета¶
In [3]:
df = pd.read_csv('dataset.csv', index_col=0)
In [4]:
df.head()
Out[4]:
| airline | flight | source_city | departure_time | stops | arrival_time | destination_city | class | duration | days_left | price | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | SpiceJet | SG-8709 | Delhi | Evening | zero | Night | Mumbai | Economy | 2.17 | 1 | 5953 |
| 1 | SpiceJet | SG-8157 | Delhi | Early_Morning | zero | Morning | Mumbai | Economy | 2.33 | 1 | 5953 |
| 2 | AirAsia | I5-764 | Delhi | Early_Morning | zero | Early_Morning | Mumbai | Economy | 2.17 | 1 | 5956 |
| 3 | Vistara | UK-995 | Delhi | Morning | zero | Afternoon | Mumbai | Economy | 2.25 | 1 | 5955 |
| 4 | Vistara | UK-963 | Delhi | Morning | zero | Morning | Mumbai | Economy | 2.33 | 1 | 5955 |
Общая информация о датасете, необходимая для дальнейших действий¶
In [5]:
df.info()
<class 'pandas.core.frame.DataFrame'> Index: 300153 entries, 0 to 300152 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 airline 300153 non-null object 1 flight 300153 non-null object 2 source_city 300153 non-null object 3 departure_time 300153 non-null object 4 stops 300153 non-null object 5 arrival_time 300153 non-null object 6 destination_city 300153 non-null object 7 class 300153 non-null object 8 duration 300153 non-null float64 9 days_left 300153 non-null int64 10 price 300153 non-null int64 dtypes: float64(1), int64(2), object(8) memory usage: 27.5+ MB
In [6]:
df.shape
Out[6]:
(300153, 11)
In [7]:
df.columns
Out[7]:
Index(['airline', 'flight', 'source_city', 'departure_time', 'stops',
'arrival_time', 'destination_city', 'class', 'duration', 'days_left',
'price'],
dtype='object')
In [8]:
df['stops'].unique()
Out[8]:
array(['zero', 'one', 'two_or_more'], dtype=object)
Анализ пропусков и дубликатов¶
Пропуски¶
In [9]:
print("Количество пропусков в абсолютных и относительных значениях:")
display(pd.DataFrame({
'Total NaN': df.isna().sum(),
'Percentage NaN': df.isna().mean() * 100
}).style.background_gradient('coolwarm').format({'Percentage NaN': '{:.2f}%'}))
Количество пропусков в абсолютных и относительных значениях:
| Total NaN | Percentage NaN | |
|---|---|---|
| airline | 0 | 0.00% |
| flight | 0 | 0.00% |
| source_city | 0 | 0.00% |
| departure_time | 0 | 0.00% |
| stops | 0 | 0.00% |
| arrival_time | 0 | 0.00% |
| destination_city | 0 | 0.00% |
| class | 0 | 0.00% |
| duration | 0 | 0.00% |
| days_left | 0 | 0.00% |
| price | 0 | 0.00% |
Дубликаты¶
In [10]:
df.duplicated().sum()
Out[10]:
np.int64(0)
Датасет чистый, так что результаты ожидаемы
Распределения числовых столбов¶
In [11]:
num_cols = ['duration', 'days_left', 'price']
fig = go.Figure()
# Добавляем гистограмму и KDE для каждой переменной
for col in num_cols:
# Гистограмма
fig.add_trace(go.Histogram(
x=df[col], name=f"{col} (гистограмма)", histnorm='probability density',
opacity=0.6, visible=False
))
# KDE-кривая
x_values = np.linspace(df[col].min(), df[col].max(), 100) # Линейная сетка значений
kde = st.gaussian_kde(df[col]) # Оценка плотности
kde_y = kde(x_values)
# Нормируем KDE-кривую к гистограмме
fig.add_trace(go.Scatter(
x=x_values, y=kde_y, mode='lines', name=f"{col} (KDE)", visible=False
))
# Делаем первую пару графиков видимой (гистограмма + KDE)
fig.data[0].visible = True
fig.data[1].visible = True
# Создаем кнопки для переключения
buttons = []
for i, col in enumerate(num_cols):
# Создаем список видимости: True только для текущей пары графиков (гистограмма + KDE)
visibility = [False] * (2 * len(num_cols)) # Две трассы (гистограмма + KDE) на каждую переменную
visibility[2 * i] = True # Делаем видимой гистограмму
visibility[2 * i + 1] = True # Делаем видимой KDE
buttons.append(dict(
label=col,
method='update',
args=[{'visible': visibility}, {'title': f"Распределение: {col}"}]
))
# Добавляем меню с кнопками
fig.update_layout(
updatemenus=[{'buttons': buttons, 'direction': 'down', 'showactive': True}],
title=f"Распределение: {num_cols[0]}",
xaxis_title="Значение",
yaxis_title="Плотность",
xaxis=dict(exponentformat='none'),
yaxis=dict(exponentformat='none'),
autosize=True
)
fig.show()